import * as React from 'react';
import './Hello.css';

export interface Props {
  name: string;
  enthusiasmLevel?: number;
}
// interface,确实可以作为形状来看待，可以形容参数，类包含的部分属性，公共部分的形状
// interface用法就和类型一样啦
interface Ntertest {
  label: string,
  body?: string, // ？表示属性可选，不必须存在
  length?: number, // 可选参数的好处，1.预定义类型（必须），2.拼写提示
}

interface Ntfobj extends Ntertest { // 接口可以继承，类是模块级别的抽象，接口是成员集合级别的抽象，继承则是抽象的一种手段
  x: number,
  readonly y: number, // 属性中的常量用readonly，只能初始化，不能后改
  [propName: string]: any, // key为string 值为任意
}



interface Arr3 {// 索引1与'1'是一样的
  x: number,  // 字符串索引，即pp['x']
              // 如果字符串索引时，索引值不可能是数字，那么两类索引的返回值类型可以任意
              // 如果字符串缩影有可能和数字索引的key相同，那么返回类型也必须相同
  [propName: number]: string, // 数字索引，即pp[1]
}
// 接口作为类型的集合（描述形状），还可以描述类属性
class Clock implements Ntertest,Arr3 {
  public label: string;
  public x: number;
  [propName: number]: string;
}

const aaa =  new Clock()
aaa[1] = '1';

const pp: Arr3 = {
  x: 11,
  0: "00",
  1: "11",
}
const testf = (arg: Ntertest): Ntertest => {
  return {
    label: '123',
    length: 123,
  }
}
const tt = testf;


// tslint:disable-next-line:max-classes-per-file
class Greeter {
  public static standardGreeting = "Hello, there";
  public greeting: string;
  public greet() {
      if (this.greeting) {
          return "Hello, " + this.greeting;
      }
      else {
          return Greeter.standardGreeting;
      }
  }
}

let greeter1: Greeter;
greeter1 = new Greeter();
console.log(greeter1.greet());

const greeterMaker: typeof Greeter = Greeter;
greeterMaker.standardGreeting = "Hey there!";

const greeter2: Greeter = new greeterMaker();
console.log(greeter2.greet());

function Hello({ name, enthusiasmLevel = 1 }: Props) {
  if (enthusiasmLevel <= 0) {
    throw new Error('You could be a little more enthusiastic. :D');
  }

  let str: string = 'yang';
  str = ' hello yang';

  console.log('111')
  fetch(`https://cn.bing.com/images/search?q=haha&FORM=HDRSC2`)
  // let bb: boolean = false;
  // let n1: number = 6;
  // let n2: number = 0xf00d;
  // let n3: number = 0xb0101;
  // let n4: number = 0o774;
  // let name: string = 'yangdechao';
  // let arr1: number[] = [1,2,3,4];
  // let arr2: Array<number> = [1,2,3,4];
  const xx: [string, number, boolean] = ['123', 123, false];
  xx[2] = true;
  xx[3] = 555;
  xx[4] = '777';// 指定的前面几位必须循序类型一致，后续越界元素的类型是元祖中所有类型的联合类型
  enum Color {red = 1, green, bulue};  // 默认从0编号，可以手动赋值
  const c: Color = Color.bulue; // 可以赋值整数或枚举类，此时Color与number类似
  const cname: string =  Color[2] // 枚举值给string变量，可以得到枚举名
  // tslint:disable-next-line:one-variable-per-declaration
  let aany:any = 4;
  aany = '000';

  const rd: Ntfobj = {x:232,y:222, z:123, label:'123'};
  rd.x = 123;
  return (
    <div className="hello">
      <div className="greeting">
        Hello {name + str + getExclamationMarks(enthusiasmLevel)}
        {xx.toString()}
        {Color.bulue}
        {c+cname+aany}
        {/* // 虽然顺序可以变，但数量必须完全一致，除非有可选参数 */}
        {tt({label: 'ok', body: '2123', length: 123}).toString()} 
        <br/>
        {rd.toString()}
        {pp[1]}
        {console.log(aaa)}
      </div>
    </div>
  );
}

export default Hello;

// helpers

function getExclamationMarks(numChars: number) {
  return Array(numChars + 1).join('!');
}